package org.ala.tcp_feign_server.context;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.ala.tcp_feign_common.config.AttrbuteKeyNamespace;
import org.ala.tcp_feign_common.config.TcpFeignConfigure;
import org.ala.tcp_feign_common.enums.TcpFeignCloseTypeEnums;
import org.ala.tcp_feign_common.logs.LoggerFactory;
import org.ala.tcp_feign_common.msg.close.CloseByteMessage;
import org.ala.tcp_feign_common.serialize.ISerializabler;
import org.ala.tcp_feign_common.serialize.kryo.KryoSerializabler;
import org.ala.tcp_feign_server.ITcpFeignServer;
import org.ala.tcp_feign_server.context.executor.TcpFeignServerExecutorMapper;
import org.ala.tcp_feign_server.context.executor.TcpFeignServerExecutorThreadPool;
import org.ala.tcp_feign_server.context.heart.WaitForHeartQueue;
import org.ala.tcp_feign_server.context.login.WaitForLoginQueue;
import org.ala.tcp_feign_server.impl.DefaultTcpFeignServer;
import org.slf4j.Logger;

import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.util.AttributeKey;


/**
 * tcp-feign 服务端环境
 *
 * @author 骆毅(ala)
 * @date 2024年4月18日
 */
public class TcpFeignServerContext {

	
	static Logger log = LoggerFactory.getLogger("tcp-feign", "server");
	
	
	/**
	 * 单利
	 */
	static TcpFeignServerContext _instance;
	public static TcpFeignServerContext instance() {
		if (_instance == null) {
			synchronized (TcpFeignServerContext.class) {
				if (_instance == null) {
					_instance = new TcpFeignServerContext();
				}
			}
		}
		return _instance;
	}
	
	
	/**
	 * 当前活跃channel
	 */
	protected Map<ChannelId, Channel> activeChannelMapper;
	/**
	 * 当前活跃连接数
	 */
	protected AtomicInteger count = new AtomicInteger(0);
	/**
	 * 等待登录队列
	 */
	protected WaitForLoginQueue loginQueue;
	/**
	 * 心跳检测队列
	 */
	protected WaitForHeartQueue heartQueue;
	/**
	 * 当前配置信息
	 */
	protected TcpFeignConfigure config;
	/**
	 * 服务端
	 */
	protected ITcpFeignServer server;
	
	
	/**
	 * 执行线程池
	 */
	protected TcpFeignServerExecutorThreadPool executorThreadPool;
	/**
	 * 执行器mapper
	 */
	protected TcpFeignServerExecutorMapper executorMapper;
	/**
	 * 序列化/反序列化工具
	 */
	protected ISerializabler serializabler;
	
	
	/**
	 * 初始化
	 */
	public void init(TcpFeignConfigure config) {
		this.config = config;
		
		activeChannelMapper = new ConcurrentHashMap<>(config.getMaxConnecton());
		
		loginQueue = new WaitForLoginQueue();
		loginQueue.init(config.getHeartInterval() * config.getAllowNoHeartTimes());
		
		heartQueue = new WaitForHeartQueue();
		heartQueue.init(config.getHeartInterval(), config.getAllowNoHeartTimes());
		
		executorThreadPool = new TcpFeignServerExecutorThreadPool(config.getCommonBizThreadPoolCoreSize(), config.getCommonBizThreadPoolMaxSize(), config.getCommonBizThreadPoolQueueSize());
		executorMapper = new TcpFeignServerExecutorMapper();
		
		//	目前只支持kryo
		serializabler = new KryoSerializabler();
		
		server = new DefaultTcpFeignServer();
	}
	/**
	 * 开启服务端
	 */
	public void startServer() {
		server.start(config);
	}
	/**
	 * 关闭服务端
	 */
	public void closeServer() {
		server.close();
	}
	
	
	/**
	 * 注册新的连接
	 */
	public void register(Channel channel) {
		if (count.get() > config.getMaxConnecton()) {
			closeClient(channel, TcpFeignCloseTypeEnums.MAX_CONNECTION);
		} else {
			//	放入等待登录队列
			channel.attr(AttributeKey.valueOf(AttrbuteKeyNamespace.CONNECT_TIMESTAMP)).set(System.currentTimeMillis());
			count.incrementAndGet();
			loginQueue.append(channel);
		}
	}
	/**
	 * 登录成功
	 */
	public void loginSuccess(Channel channel) {
		//	打标登录成功
		channel.attr(AttributeKey.valueOf(AttrbuteKeyNamespace.LOGIN)).set(true);
		//	放入活跃集合
		activeChannelMapper.put(channel.id(), channel);
	}
	/**
	 * 关闭客户端连接
	 */
	public void closeClient(Channel channel, TcpFeignCloseTypeEnums type) {
		if (channel.isActive()) {
			channel.eventLoop().execute(() -> channel.writeAndFlush(CloseByteMessage.build(type)));
		}
		channel.close();
		activeChannelMapper.remove(channel.id());
		count.decrementAndGet();
	}
	
	
	public TcpFeignConfigure getConfig() {
		return config;
	}
	public void setConfig(TcpFeignConfigure config) {
		this.config = config;
	}
	public Map<ChannelId, Channel> getActiveChannelMapper() {
		return activeChannelMapper;
	}
	public void setActiveChannelMapper(Map<ChannelId, Channel> activeChannelMapper) {
		this.activeChannelMapper = activeChannelMapper;
	}
	public TcpFeignServerExecutorThreadPool getExecutorThreadPool() {
		return executorThreadPool;
	}
	public TcpFeignServerExecutorMapper getExecutorMapper() {
		return executorMapper;
	}
	public ISerializabler getSerializabler() {
		return serializabler;
	}
	
	
}
